<?php

/**
 * 检测用户是否登录，未登录-0,
 * @return number
 */
function is_login()
{
    $user = session('member_auth');
    
    if (empty($user)) 
        return 0;
    else
        return session('member_auth_sign') == data_auth_sign($user) ? $user['id'] : 0;
}

/**
 * 数据签名验证
 * @param array $data
 * @return string
 */
function data_auth_sign($data)
{
    // 数据类型检测
    is_array($data) || (array) $data;
    
    /* 排序 */ 
    ksort($data); 

    /* URL编码陈query字符串 */
    $code = http_build_query($data);
    
    /* 生成签名 */
    $sign = sha1($code);
    
    return $sign;
}

/**
 * 会员密码加密
 * @param string $username
 * @param string $password
 * @param string $key       混淆字符串
 * @return false | string
 */
function password_encrypt($username, $password, $key = '')
{
    // 用户名或密码为空，返回false
    if (empty(trim($username)) || empty(trim($password))) return false;
    
    $key = empty(trim($key)) ? '' : md5($key);
    return md5( md5($username) . $key . md5(md5($password)));
}

/**
 * 将数据哈希化,MD5
 * @param mixed $data
 * @param string $key
 * @return boolean|string
 */
function hashed($data, $key = '') 
{
    if (empty(trim($data))) return false;
    
    $key = empty(trim($key)) ? '' : md5($key);
    return md5($key . md5($data));
}

/**
 * RSA加密
 * @param mixed $data           原始数据
 * @param string $key           混淆信息
 * @param string $public_key    rsa公钥，公钥与私钥必须选择一个
 * @param string $private_key   rsa私钥
 * @param number $expire        数据有效期，0-无限期
 * @return boolean|string
 */
function rsa_encrypt($data, $key, $public_key = false, $private_key = false, $expire = 0)
{
    // 必须选择一个加密密钥
    if (false === $private_key && false === $public_key) return false;

    $crypted = false;
    // 优先使用公钥加密
    if (false !== $public_key) {
        openssl_public_encrypt($data, $crypted, $public_key);
    } elseif (false !== $private_key) {
        openssl_private_encrypt($data, $crypted, $private_key);
    }
    
    // 加密失败
    if (false === $crypted) return false;
    
    \Think\Crypt::init('Base64');
    $crypted = \Think\Crypt::encrypt($crypted, $key, $expire);
    
    // 转化为URL安全的Base64
    $crypted = base64_encode($crypted);
    $crypted = str_replace(array('+', '/', '='), array('-', '_', ''), $crypted);
    
    return $crypted;
    
}

/**
 * RSA解密
 * @param mixed $data           原始数据
 * @param string $key           混淆字符
 * @param string $private_key   私钥
 * @param string $public_key    公钥
 * @return boolean|mixed
 */
function rsa_decrypt($data, $key, $private_key = false, $public_key = false)
{
    // 必须至少提供一个解密密钥
    if (false === $private_key && false === $public_key) return false;
    
    // base64解码
    $data = str_replace(array('-', '_'), array('+', '/'), $data);
    $mod4 = strlen($data)%4;
    $mod4 && $data .= substr('====', $mod4);
    $data = base64_decode($data);
    
    \Think\Crypt::init('Base64');
    $data = \Think\Crypt::decrypt($data, $key);
    
    $decrypted = false;
    // 优先使用私钥解密
    if (false !== $private_key) {
        openssl_private_decrypt($data, $decrypted, $private_key);
    } elseif (false !== $public_key) {
        openssl_public_decrypt($data, $decrypted, $public_key);
    }
    
    return $decrypted;
}

/**
 * 将数组数据返回为树状格式数据
 * @param araay $list       原始数组
 * @param string $pk        数据标识符
 * @param string $parent_key父标识符
 * @param string $child     处理完毕后子数据键
 * @param number $root      根节点pid
 * @return array
 */
function list2tree($list, $pk = 'id', $parent_key = 'pid', $child = 'child', $root = 0)
{
    $tree = array();
    if (is_array($list)) {
        
        /* 创建基于主键的数组引用 */
        $refer = array();
        foreach ($list as $key=>$data) {
            $refer[$data[$pk]] = & $list[$key];
        }
        
        foreach ($list as $key=>$data) {
            /* 判断是否存在parent */
            $parentId = $data[$parent_key];
            
            if ($root == $parentId) {
                $tree[] = & $list[$key];
            } else {
                if (isset($refer[$parentId])) {
                    $parent = & $refer[$parentId];
                    $parent[$child][] = & $list[$key];
                }
            }
        }
    }
    
    return $tree;
}

/**
 * 将list2tree的树状数据还原为列表数据
 * @param array $tree      原始数据
 * @param string $child     子节点键名
 * @param string $order     排序键
 * @param array $list       过渡用的中间数组
 * @return array()
 */
function tree2list($tree, $child = 'child', $order='id', &$list = array())
{
    if (is_array($tree)) {
        $refer = array();
        foreach ($tree as $key=>$value) {
            $refer = $value;
            if (isset($refer[$child])) {
                unset($refer[$child]);
                tree2list($value[$child], $child, $order, $list);
            }
            $list[] = $refer;
        }
        $list = list_sort_by($list, $order, $sortby = 'asc');
    }
    return $list;
}

/**
 * 对查询结果进行排序
 * @param array $list       原始数据
 * @param string $field     排序的字段名
 * @param string $sortby    排序方式，asc,desc,nat
 * @return array|boolean
 */
function list_sort_by($list, $field, $sortby = 'asc')
{
    if (is_array($list)) {
        $refer = $resulrSet = array();
        foreach ($list as $i=>$data) {
            $refer[$i] = &$data[$field];
        }
        
        switch ($sortby) {
            case 'asc': asort($refer); break;
            case 'desc': arsort($refer); break;
            case 'nat': natcasesort($refer); break;
        }
        
        foreach ($refer as $key=>$val) {
            $resulrSet[] = & $list[$key];
        }
        
        return $resulrSet;
    }
    
    return false;
}

/**
 * 时间戳格式化
 * @param string $time      时间戳
 * @param boolean           是否展示为友好格式
 * @param string $format    格式
 * @return string
 */
function time_format($time = null, $friendly = false, $format = 'Y-m-d H:i') 
{
    if ($time == 0) return '';
    $time = $time === null ? NOW_TIME : intval($time);
    
    // 格式化时间为xx分钟前，xx小时前，x天前
    $desc = date($format, $time);
    if ($friendly) {
        $rtime = date('m-d H:i', $time);
        $htime = date('H:i', $time);
        
        $time  = time() -$time;
        
        if ($time < 60) {
            $desc = '刚刚';
        } elseif ($time < 60 * 60) {
            $desc = floor($time / (60 * 60)) . '分钟前';
        } elseif ($time < 24 * 60 * 60) {
            $desc = floor($time/60*60) . '小时前 ' . $htime;
        } elseif ($time < 24 * 3 * 60 * 60) {
            $d = floor($time/(60 * 60 * 24));
            if ($d == 1) 
                $desc = '昨天 ' . $rtime;
            else 
                $desc = '前天 ' . $rtime;
        }
    }
    
    return $desc;
}


/**
 * 人民币小写转大写
 * @param string $number        数值
 * @param string $init_unit     币种单位，默认“元”
 * @param string $is_round      是否对小数进行四舍五入
 * @param string $is_extra_zero 是否对整数部分以0结尾，小数存在的数字附加0，如1960.30，有的系统要求输入“壹仟玖佰陆拾元零叁角”，实际上“壹仟玖佰陆拾元叁角”也是对的
 * @return string
 */
function num2cny($number = 0, $init_unit='元', $is_round = true, $is_extra_zero = false)
{
    // 将数字切分成两段
    $parts  = explode('.', $number, 2);
    $int    = isset($parts[0]) ? strval($parts[0]) : '0';   // 整数部分
    $dec    = isset($parts[1]) ? strval($parts[1]) : '';    // 小数部分

    // 如果小数点多于2位，不四舍五入就直接截取，否则就处理
    $dec_len = strlen($dec);
    if(isset($parts[1]) && $dec_len > 2) {
        $dec = $is_round
        ? substr(strrchr(strval(round(floatval("0.".$dec), 2)), '.'), 1)
        : substr($parts[1], 0, 2);
    }

    // 当number为0.001时。小数点后的金额为0元
    if(empty($int) && empty($dec)) {
        return '零';
    }

    // 定义
    $chs = array('0', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖');
    $uni = array('', '拾', '佰', '仟');    // 整数部分单位
    $dec_uni = array('角', '分');         // 小数部分单位
    $exp = array('', '万');
    $res = '';

    // 从整数部分向右查找
    for($i = strlen($int)-1, $k=0; $i>=0; $k++ ) {
        $str = '';

        // 按照中文读写习惯，每4个字为一段进行转化，i一直在减
        for($j=0; $j<4 && $i>=0; $j++, $i--) {
            $u = $int{$i} > 0 ? $uni[$j] : ''; // 非零的数字后面添加单位
            $str = $chs[$int{$i}] . $u . $str;
        }

        $str = rtrim($str, '0'); // 去掉末尾的0
        $str = preg_replace('/0+/', '零', $str); // 替换多个连续的0
        isset($exp[$k]) || $exp[$k] = $exp[$k-2] . '亿'; // 构建单位

        $u2  = $str == '' ? '' : $exp[$k];
        $res = $str . $u2 . $res;
    }

    // 如果小数部分处理完后是00，需要处理下
    $dec = rtrim($dec, '0');

    // 小数部分从左向右找
    if(!empty($dec)) {
        $res .= $init_unit;

        // 是否要在整数部分以0结尾的数字后附加0，有的系统这样要求
        if ($is_extra_zero) {
            substr($int, -1) === '0' && $res.= '零';
        }

        for($i=0, $cnt = strlen($dec); $i<$cnt; $i++) {
            $u = $dec{$i} > 0 ? $dec_uni[$i] : '';// 非0的数字后面添加单位
            $res .= $chs[$dec{$i}] . $u;
        }

        $res = rtrim($res, '0'); // 去掉末尾的0
        $res = preg_replace('/0+/', '零', $res); // 替换多个连续的0
    } else {
        $res .= $init_unit . '整';
    }

    return $number < 0 ? '(负)'.$res : $res;
}

/**
 * 验证身份证的有效性
 * @param mixed $id
 * @return boolean
 */
function idcardVerify($id)
{
    $id     = strtoupper($id);
    $regx   = '/(^\d{15}$)|(^\d{17}([0-9]|X)$)/';
    $arr_split=array();

    if(!preg_match($regx, $id)) {
        return false;
    }

    if(15 == strlen($id)) {
        // 15位身份证
        $regx = '/^(\d{6}+(\d{2})+(\d{2})+(\d{2})+(\d{3}))$/';
        @preg_match($regx, $id, $arr_split);

        // 检查生日日期是否正确
        $birthday = "19{$arr_split[2]}/{$arr_split[3]}/{$arr_split[4]}";
        if(!strtotime($birthday)) {
            return false;
        } else {
            return true;
        }
    } else {
        // 18位身份证
        $regx = '/^(\d{6})+(\d{4})+(\d{2})+(\d{2})+(\d{3})+([0-9]|X)$/';
        @preg_match($regx, $id, $arr_split);
        $birthday = "{$arr_split[2]}/{$arr_split[3]}/{$arr_split[4]}";
        // 检查生日是否合法
        if(!strtotime($birthday)) {
            return false;
        } else {
            // 检验18位身份证的校验码是否正确
            // 校验位按照ISO 7064:1983.MOD 11-2的规定生成，X可以认为是数字10
            $arr_int= array(7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2);
            $arr_ch = array('1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2');
            $sign   = 0;

            for($i=0; $i<17; $i++) {
                $b = (int) $id{$i};
                $w = $arr_int[$i];
                $sign += $b * $w;
            }

            $n = $sign % 11;
            $val_num = $arr_ch[$n];
            if($val_num != substr($id, 17, 1)) {
                return false;
            } else {
                return true;
            }
        }
    }

}
